/**
  *****************************************************************************
  * @file 
  * @brief 
  * @author luffy
  * @version V1.0.0
  * @date 2022/12/01
  *****************************************************************************
  */
 /* Includes -----------------------------------------------------------------*/
#include "dev_ad7193_temp.h"	
#include "func_pt100.h"
#include "led_task.h"

/* Private defines ----------------------------------------------------------*/
#define   AD7193_REF     2.5f
/* Private Struct -----------------------------------------------------------*/

/* Private enum -------------------------------------------------------------*/

/* Private Variable ---------------------------------------------------------*/
//Pointer

//Array
static unsigned char currentPolarity = 0;
static unsigned char currentGain     = 1;
//Const

/* Private function prototypes ----------------------------------------------*/



/***************************************************************************//**
 * @brief Writes data into a register.
 *
 * @param registerAddress - Address of the register.
 * @param registerValue - Data value to write.
 * @param bytesNumber - Number of bytes to be written.
 * @param modifyCS - Allows Chip Select to be modified.
 *
 * @return none.
*******************************************************************************/
static void AD7193_SetRegisterValue(dev_adc7193_t* this,
						     unsigned char registerAddress,
                             unsigned long registerValue,
                             unsigned char bytesNumber)
{
    unsigned char writeCommand[5] = {0, 0, 0, 0, 0};
    unsigned char* dataPointer    = (unsigned char*)&registerValue;
    unsigned char bytesNr         = bytesNumber;
    uint8_t byteRead = 0;
	
    writeCommand[0] = AD7193_COMM_WRITE |
                      AD7193_COMM_ADDR(registerAddress);
    while(bytesNr > 0)
    {
        writeCommand[bytesNr] = *dataPointer;
        dataPointer ++;
        bytesNr --;
    }
	
	//this->private.cs.Write(&this->private.cs, 0);	
	
	this->private.spi.ReadWrite(&this->private.spi, &writeCommand[0], &byteRead, 1);  //发送写命令
	
	for(int i = 1; i < bytesNumber + 1; i++) 
    {
        this->private.spi.ReadWrite(&(this->private.spi), &writeCommand[i], &byteRead, 1);  //循环读数
    }
	
	//this->private.cs.Write(&this->private.cs, 1);	
}

/***************************************************************************//**
 * @brief Reads the value of a register.
 *
 * @param registerAddress - Address of the register.
 * @param bytesNumber - Number of bytes that will be read.
 * @param modifyCS    - Allows Chip Select to be modified.
 *
 * @return buffer - Value of the register.
*******************************************************************************/
static unsigned long AD7193_GetRegisterValue(dev_adc7193_t* this,
								      unsigned char registerAddress,
                                      unsigned char bytesNumber)
{
    #if defined NEW_HARDWARE_WITH_ERROR_SPI
    unsigned char buffer[5] = {0, 0, 0, 0, 0}; 
	unsigned char beforeConvertedData = 0; 
    unsigned long registerData = 0x0;
    unsigned char i = 0, byteWrite = 0, byteRead = 0;
    
    byteWrite = AD7193_COMM_READ | AD7193_COMM_ADDR(registerAddress);
	
	//this->private.cs.Write(&this->private.cs, 0);
	
	this->private.spi.ReadWrite(&this->private.spi, &byteWrite, &byteRead, 1);  //发送读取命令
	
	byteWrite = 0XFF;
	for(i = 0; i < bytesNumber; i++) 
    {
        this->private.spi.ReadWrite(&(this->private.spi), &byteWrite, &beforeConvertedData, 1);  //循环读数
		
		buffer[i] = ~beforeConvertedData;
	}
	
	//this->private.cs.Write(&this->private.cs, 1);
	
    for(i = 0; i < bytesNumber; i++) 
    {
        registerData = (registerData << 8) + buffer[i];
    }
    
    return registerData;
    
    #else
    unsigned char buffer[5] = {0, 0, 0, 0, 0}; 
    unsigned long registerData = 0x0;
    unsigned char i = 0, byteWrite = 0, byteRead = 0;
    
    byteWrite = AD7193_COMM_READ | AD7193_COMM_ADDR(registerAddress);
	
	//this->private.cs.Write(&this->private.cs, 0);
	
	this->private.spi.ReadWrite(&this->private.spi, &byteWrite, &byteRead, 1);  //发送读取命令
	
	byteWrite = 0XFF;
	for(i = 0; i < bytesNumber; i++) 
    {
        this->private.spi.ReadWrite(&(this->private.spi), &byteWrite, &buffer[i], 1);  //循环读数
	}
	
	//this->private.cs.Write(&this->private.cs, 1);
	
    for(i = 0; i < bytesNumber; i++) 
    {
        registerData = (registerData << 8) + buffer[i];
    }
    
    return registerData;    
    #endif
  
}



/***************************************************************************//**
 * @brief Resets the device.
 *
 * @return none.
*******************************************************************************/
static void AD7193_Reset(dev_adc7193_t* this)
{
    unsigned char byteWrite, byteRead;
    
	byteWrite = 0xFF;
	
    #if defined NEW_HARDWARE_WITH_ERROR_SPI
	this->private.cs.Write(&this->private.cs, 1);
	#else
    this->private.cs.Write(&this->private.cs, 0);
    #endif
    
	for(uint8_t i = 0; i < 5; i++) 
    {
        this->private.spi.ReadWrite(&(this->private.spi), &byteWrite, &byteRead, 1);  //循环发
    }
	
	//this->private.cs.Write(&this->private.cs, 1);
	
	
}

/***************************************************************************//**
 * @brief Set device to idle or power-down.
 *
 * @param pwrMode - Selects idle mode or power-down mode.
 *                  Example: 0 - power-down
 *                           1 - idle
 *
 * @return none.
*******************************************************************************/
static void AD7193_SetPower(dev_adc7193_t* this, unsigned char pwrMode)
{
     unsigned long oldPwrMode = 0x0;
     unsigned long newPwrMode = 0x0; 
 
     oldPwrMode = AD7193_GetRegisterValue(this, AD7193_REG_MODE, 3);
	
     oldPwrMode &= ~(AD7193_MODE_SEL(0x7));
     newPwrMode = oldPwrMode | 
                  AD7193_MODE_SEL((pwrMode * (AD7193_MODE_IDLE)) |
                                  (!pwrMode * (AD7193_MODE_PWRDN)));
	
     AD7193_SetRegisterValue(this, AD7193_REG_MODE, newPwrMode, 3);  
}

/***************************************************************************//**
 * @brief Waits for Status Register RDY Bit to go 0.
 *
 * @return none.
*******************************************************************************/
static void AD7193_WaitReady(dev_adc7193_t* this)
{
	uint8_t status = 0x0;
	int retry_count = 100000;
	
	
	status = AD7193_GetRegisterValue(this, AD7193_REG_STAT, 1);
	status = (status >> 7) & 1;

    while(status)
    {
		status = AD7193_GetRegisterValue(this, AD7193_REG_STAT, 1);
		status = (status >> 7) & 1;
		
		retry_count--;
		if(retry_count <= 0)
		{
            #if defined SUPPORT_LED_EXPAND
			ExpandLed_Light(BLUE, S1);
			ExpandLed_Light(BLUE, S2);
			ExpandLed_Light(BLUE, S3);
            #endif
			break;
		}
        
    }
	
}

/***************************************************************************//**
 * @brief Selects the channel to be enabled.
 *
 * @param channel - Selects a channel.
 *                  Example: AD7193_CH_0 - AIN1(+) - AIN2(-);  (Pseudo = 0)
 *                           AD7193_CH_1 - AIN3(+) - AIN4(-);  (Pseudo = 0)
 *                           AD7193_TEMP - Temperature sensor
 *                           AD7193_SHORT - AIN2(+) - AIN2(-); (Pseudo = 0)
 *  
 * @return none.
*******************************************************************************/
static void AD7193_ChannelSelect(dev_adc7193_t* this, unsigned short channel,uint8_t is_use_peeudo_diff)
{
    if(is_use_peeudo_diff)
    {
        unsigned long oldRegValue = 0x0;
        unsigned long newRegValue = 0x0;   
         
        oldRegValue = AD7193_GetRegisterValue(this, AD7193_REG_CONF, 3);
        
        oldRegValue &= ~(AD7193_CONF_CHAN(0x3FF));
        newRegValue = oldRegValue | AD7193_CONF_CHAN(1 << channel);   
        
        //newRegValue |= AD7193_CONF_REFSEL; 
        newRegValue &= (~AD7193_CONF_REFSEL);  //1：REFIN2 Reference(内部温度用REFIN1基准电压，采样电压用REFIN2)
        
        newRegValue |= AD7193_CONF_PSEUDO;
        
        AD7193_SetRegisterValue(this, AD7193_REG_CONF, newRegValue, 3);
    }
    else
    {
        unsigned long oldRegValue = 0x0;
        unsigned long newRegValue = 0x0;   
         
        oldRegValue = AD7193_GetRegisterValue(this, AD7193_REG_CONF, 3);
        
        oldRegValue &= ~(AD7193_CONF_CHAN(0x3FF));
        newRegValue = oldRegValue | AD7193_CONF_CHAN(1 << channel);   
        
        //newRegValue &= (~AD7193_CONF_REFSEL);
        newRegValue |= AD7193_CONF_REFSEL;  //1：REFIN2 Reference(内部温度用REFIN1基准电压，采样电压用REFIN2)
        
        AD7193_SetRegisterValue(this, AD7193_REG_CONF, newRegValue, 3);
    }
}

static void AD7193_ChannelSelect2(dev_adc7193_t* this, unsigned short channel)
{
    unsigned long oldRegValue = 0x0;
    unsigned long newRegValue = 0x0;   
     
    oldRegValue = AD7193_GetRegisterValue(this, AD7193_REG_CONF, 3);
	
    oldRegValue &= ~(AD7193_CONF_CHAN(0x3FF));
    newRegValue = oldRegValue | AD7193_CONF_CHAN(1 << channel);   
	
	newRegValue &= ~AD7193_CONF_REFSEL; 
	//newRegValue |= AD7193_CONF_REFSEL;  //1：REFIN2 Reference(内部温度用REFIN1基准电压，采样电压用REFIN2)
	
    AD7193_SetRegisterValue(this, AD7193_REG_CONF, newRegValue, 3);
}

/***************************************************************************//**
 * @brief Performs the given calibration to the specified channel.
 *
 * @param mode - Calibration type.
 * @param channel - Channel to be calibrated.
 *
 * @return none.
*******************************************************************************/
static void AD7193_Calibrate(dev_adc7193_t* this, unsigned char mode, unsigned char channel)
{
    unsigned long oldRegValue = 0x0;
    unsigned long newRegValue = 0x0;
    
    AD7193_ChannelSelect(this, channel,0);
	
    oldRegValue = AD7193_GetRegisterValue(this, AD7193_REG_MODE, 3);
	
    oldRegValue &= ~AD7193_MODE_SEL(0x7);
    newRegValue = oldRegValue | AD7193_MODE_SEL(mode);
	
	//this->private.cs.Write(&this->private.cs, 0);
	
    AD7193_SetRegisterValue(this, AD7193_REG_MODE, newRegValue, 3); // CS is not modified.
    
	AD7193_WaitReady(this);
	
	//this->private.cs.Write(&this->private.cs, 1);
}

/***************************************************************************//**
 * @brief Selects the polarity of the conversion and the ADC input range.
 *
 * @param polarity - Polarity select bit. 
                     Example: 0 - bipolar(双极性) operation is selected.
                              1 - unipolar operation is selected.
* @param range - Gain select bits. These bits are written by the user to select 
                 the ADC input range.     
 *
 * @return none.
*******************************************************************************/
static void AD7193_RangeSetup(dev_adc7193_t* this, unsigned char polarity, unsigned char range)
{
    unsigned long oldRegValue = 0x0;
    unsigned long newRegValue = 0x0;
    static uint8_t firstIn = 1;
    
    oldRegValue = AD7193_GetRegisterValue(this, AD7193_REG_CONF,3);
	
    oldRegValue &= ~(AD7193_CONF_UNIPOLAR |
                     AD7193_CONF_GAIN(0x7));
    newRegValue = oldRegValue | 
                  (polarity * AD7193_CONF_UNIPOLAR) |
                  AD7193_CONF_GAIN(range) | AD7193_CONF_CHOP; 
	
    AD7193_SetRegisterValue(this, AD7193_REG_CONF, newRegValue, 3);
	
    if(firstIn)
    {
        SoftDelay_us(300);
        firstIn = 0;
    }
   
    /* Store the last settings regarding polarity and gain. */
    currentPolarity = polarity;
    currentGain = 1 << range;
}

/***************************************************************************//**
 * @brief Returns the result of a single conversion.
 *
 * @return regData - Result of a single analog-to-digital conversion.
*******************************************************************************/
static unsigned long AD7193_SingleConversion(dev_adc7193_t* this)
{
    unsigned long command = 0x0;
    unsigned long regData = 0x0;
 
//    command = AD7193_MODE_SEL(AD7193_MODE_SINGLE) | 
//              AD7193_MODE_CLKSRC(AD7193_CLK_INT) |
//              AD7193_MODE_RATE(0x060); 

    command = AD7193_MODE_SEL(AD7193_MODE_SINGLE) | 
              AD7193_MODE_CLKSRC(AD7193_CLK_INT) |
              AD7193_MODE_RATE(0x060);    
	
    //this->private.cs.Write(&this->private.cs, 0);
	
    AD7193_SetRegisterValue(this, AD7193_REG_MODE, command, 3); // CS is not modified.
	
    AD7193_WaitReady(this);
	
    regData = AD7193_GetRegisterValue(this, AD7193_REG_DATA, 3);
	
    //this->private.cs.Write(&this->private.cs, 1);
    
    return regData;
}

/***************************************************************************//**
 * @brief Returns the average of several conversion results.
 *
 * @return samplesAverage - The average of the conversion results.
*******************************************************************************/
static unsigned long AD7193_ContinuousReadAvg(dev_adc7193_t* this, unsigned char sampleNumber)
{
    unsigned long samplesAverage = 0;
    unsigned long command        = 0;
    unsigned char count          = 0;
        
    command = AD7193_MODE_SEL(AD7193_MODE_CONT) | 
              AD7193_MODE_CLKSRC(AD7193_CLK_INT) |
              AD7193_MODE_RATE(0x060);
	
    //this->private.cs.Write(&this->private.cs, 0);
	
    AD7193_SetRegisterValue(this, AD7193_REG_MODE, command, 3); // CS is not modified.
	
    for(count = 0; count < sampleNumber; count++)
    {
        AD7193_WaitReady(this);
        samplesAverage += AD7193_GetRegisterValue(this, AD7193_REG_DATA, 3); // CS is not modified.
    }
	
    //this->private.cs.Write(&this->private.cs, 1);
	
    samplesAverage = samplesAverage / sampleNumber;
    
    return samplesAverage;
}

/***************************************************************************//**
 * @brief Converts 24-bit raw data to volts.
 *
 * @param rawData - 24-bit data sample.
 * @param vRef - The value of the voltage reference used by the device.
 *
 * @return voltage - The result of the conversion expressed as volts.
*******************************************************************************/
static float AD7193_ConvertToVolts(unsigned long rawData, float vRef)
{
    float voltage = 0;
    
    if(currentPolarity == 0 )   // Bipolar(双极性) mode
    {
        voltage = (((float)rawData / (1ul << 23)) - 1) * vRef / currentGain;
    }
    else                        // Unipolar mode
    {
        voltage = ((float)rawData * vRef) / (1ul << 24) / currentGain;
    }
    
    return voltage;
}

/***************************************************************************//**
 * @brief Converts 24-bit raw data to volts.
 *
 * @param rawData - 24-bit data sample.
 *
 * @return voltage - The result of the conversion expressed as volts.
*******************************************************************************/
static float AD7193_ConvertToResistance(unsigned long rawData)
{
    float resistance = 0;
    
    resistance = (float)rawData / ((1ul << 24) * currentGain) * 2000;
    
    return resistance;
}
/***************************************************************************//**
 * @brief Read data from temperature sensor and converts it to Celsius degrees.
 *
 * @return temperature - Celsius degrees.
*******************************************************************************/
static unsigned long AD7193_TemperatureRead(dev_adc7193_t* this)
{
    unsigned long dataReg     = 0;
    unsigned long temperature = 0;    
    
    AD7193_ChannelSelect2(this, AD7193_CH_TEMP);
	AD7193_RangeSetup(this, 0, AD7193_CONF_GAIN_1); // Bipolar operation, 1 Gain.
    dataReg = AD7193_SingleConversion(this);
	
    dataReg -= 0x800000;
    temperature = dataReg / 2815;    // Kelvin Temperature
    temperature -= 273;              // Celsius Temperature
    
    return temperature;
}

/***********************************************************************************
 * @brief 获取AD7193测量值
 * ex:
 * @par
 * None
 * @retval 返回pt1000温度值
 **********************************************************************************/
static float AD7193_Voltage_Measurements(dev_adc7193_t* this, adc7193_ch_e channel, uint8_t sampleNumber)
{
	unsigned long dataReg     = 0;  
	float res = 0;
	
    AD7193_ChannelSelect(this, channel,1);
	AD7193_RangeSetup(this, 1, AD7193_CONF_GAIN_1); 	
	
	if(sampleNumber <= 1)
	{
		dataReg = AD7193_SingleConversion(this);   //
	}
	else
	{
		dataReg = AD7193_ContinuousReadAvg(this, sampleNumber);
	}
   
	res = AD7193_ConvertToVolts(dataReg,2.5);
	return res;
}

/***********************************************************************************
 * @brief 获取AD7193测量值
 * ex:
 * @par
 * None
 * @retval 返回pt1000温度值
 **********************************************************************************/
static float AD7193_Measurements(dev_adc7193_t* this, adc7193_ch_e channel, uint8_t sampleNumber)
{
	unsigned long dataReg     = 0;  
	float res = 0;
	float temp = 0;
	
    AD7193_ChannelSelect(this, channel,0);
	AD7193_RangeSetup(this, 1, AD7193_CONF_GAIN_1); // 单极性, 16 Gain.
	//AD7193_RangeSetup(this, 1, AD7193_CONF_GAIN_64); // 单极性, 16 Gain.
	
	
	if(sampleNumber <= 1)
	{
		dataReg = AD7193_SingleConversion(this);   //
	}
	else
	{
		dataReg = AD7193_ContinuousReadAvg(this, sampleNumber);
	}
   
	res = AD7193_ConvertToResistance(dataReg);
	PT100_R2T(res/10.0f, &temp);
	
	return temp;
}

/***************************************************************************//**
 * @brief Checks if the AD7139 part is present.
 *
 * @return status - Indicates if the part is present or not.
*******************************************************************************/
uint32_t id = 0;

/******************************************************************************
* 功能说明：温度采集ADC初始化
* 输入参数：dev_adc7193_t* this - 温度采集DAC SPI端口和读函数功能模块
* 输出参数：dev_adc7193_t* this - 温度采集DAC SPI端口和读函数功能模块
* 返回值：初始化完成返回0，否则返回-1
*******************************************************************************/
int Dev_Adc7193_Temp_Init(dev_adc7193_t* this)
{
    // spi config
	this->private.spi.DRV    	   			= this->DRV;
	this->private.spi.PIN_CS      			= this->PIN_CS;
	this->private.spi.PIN_MISO    			= this->PIN_MISO;
    this->private.spi.PIN_MOSI    			= this->PIN_MOSI;
    this->private.spi.PIN_SCK     			= this->PIN_SCK;

	this->private.spi.CS_EN       			= this->SPI_CS_MODE;
	this->private.spi.SPEED	   			    = this->SPI_SPEED;	
	this->private.spi.ORDER       			= SPI_MSB;
	this->private.spi.CPOL        			= SPI_CPOL_H;      //AD7193用的是SPI的MODE3模式
	this->private.spi.CPHA        			= SPI_CPHA_2;
	this->private.spi.TRANS       			= SPI_TRANS_BYTE;
	this->private.spi.CS_DELAY_US 			= 10;
	if(Drv_Spi_Init(&this->private.spi) < 0){
        return -1;
    }
	
	// soft cs io config
	this->private.cs.PIN 			= this->PIN_CS;
	this->private.cs.MODE			= OUTPUT_UP;
	this->private.cs.INIT_LEVEL 	= HIGHT_LEVEL;
	if(Drv_Gpio_Init(&this->private.cs) < 0){
		return -1;
	}
	
	this->Read_Balance						= AD7193_Measurements;
    this->Read_Voltage					    = AD7193_Voltage_Measurements;
	this->ReadTemp							= AD7193_TemperatureRead;
   
	AD7193_Reset(this);
	
	SoftDelay_us(500);
	
	id = AD7193_GetRegisterValue(this, AD7193_REG_ID, 1);
	
	return 0;
}

